function list(names) {
  const len = names.length
  if (!len) {
    return ''
  }
  const pluckName = item => item.name
  const AND_CONNCTER = ' & '
  if (len < 2) {
    return names.map(pluckName).join(AND_CONNCTER)
  }
  const last = names[len - 1]
  return names.slice(0, -1).map(pluckName).join(', ') + AND_CONNCTER + last.name
}

function findShort(s) {
  const re = /\s+/
  const result = s.split(re)
  if (!result) {
    return 0
  }
  return Math.min(...result.map(item => item.length))
}

function order(word) {
  // space regex
  const re = /\s+/
  const extractNumFromStr = str => Number(str.match(/\d+/)[0])
  let words = word.split(re)
  words.sort((a, b) => {
    const prev = extractNumFromStr(a)
    const next = extractNumFromStr(b)
    if (prev > next) {
      return 1
    }
    if (prev < next) {
      return -1
    }
    return 0
  })
  return words.join(' ')
}

const isSquare = n => Number.isInteger(Math.sqrt(n))

const uniqueInOrder = function(iterable) {
  let arr = Array.isArray(iterable) ? iterable : iterable.split('')
  return arr.filter((value, index, array) => {
    const nextValue = array[index + 1]
    return !nextValue ? true : nextValue !== value
  })
}

function findMissingLetter(array) {
  const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
  const isCapital = /^[A-Z]/.test(array[0])
  array = array.map(alphabet => alphabet.toLowerCase())
  for (let i = 0; i < array.length; i++) {
    if (array[i + 1] && ALPHABET[ALPHABET.indexOf(array[i]) + 2] === array[i + 1]) {
      const result = ALPHABET[ALPHABET.indexOf(array[i]) + 1]
      if (isCapital) {
        return result.toUpperCase()
      }
      return result
    }
  }
  return '';
}

function findMissingLetter(array) {
  const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
  const isCapital = /^[A-Z]/.test(array[0])
  const result = array.map(alphabet => alphabet.toLowerCase())
    .filter((alphabet, index, alphabets) => {
      return ALPHABET[ALPHABET.indexOf(alphabets[index + 1]) - 2] === alphabet
    })[0]
  const nextAlphabet = ALPHABET[ALPHABET.indexOf(result) + 1]
  return isCapital ? nextAlphabet.toUpperCase() : nextAlphabet
}

function digital_root(n) {
  const result = String(n).split('')
    .map(value => Number(value))
    .reduce((a, b) => a + b, 0)
  if (result < 10) {
    return result
  }
  return digital_root(result)
}

function titleCase(title, minorWords = '') {
  if (!title) {
    return ''
  }
  const ONE_SPACE = ' '
  const toLowerCase = value => value.toLowerCase()
  const excludes = minorWords.split(ONE_SPACE)
    .map(toLowerCase)
  const captialWord = word => word.slice(0, 1).toUpperCase() + word.slice(1)
  return title
    .split(ONE_SPACE)
    .map(toLowerCase)
    .map((value, index) => {
      if (excludes.includes(value) && index !== 0) {
        return value
      }
      return captialWord(value)
    })
    .join(ONE_SPACE)
}

function solution(number){
  if (number <= 3) {
    return 0
  }
  const startNumber = 3
  return Array(number - startNumber)
    .fill()
    .map((_, index) => index + startNumber)
    .filter(value => value % 3 === 0 || value % 5 === 0)
    .reduce((a, b) => a + b, 0)
}

function sqInRect(lng, wdth, result = []) {
  if (!result.length && wdth === lng) {
    return null
  }
  const min = Math.min(lng, wdth)
  result.push(min)
  const delta = Math.abs(lng - wdth)
  if (delta === 0) {
    return result
  }
  return sqInRect(Math.abs(lng - wdth), min, result)
}

function sqInRect(length, width) {
  if (length === width) {
    return null
  }
  return sqInRectDeep(length, width)
}


function sqInRectDeep(length, width) {
  if (length === width) {
    return [width]
  }
  return [Math.min(length, width)].concat(sqInRectDeep(Math.abs(length - width), Math.min(length, width)))
}

const MORSE_CODE = [ '-.-.--': '!',
  '.-..-.': '"',
  '...-..-': '$',
  '.-...': '&',
  '.----.': '\'',
  '-.--.': '(',
  '-.--.-': ')',
  '.-.-.': '+',
  '--..--': ',',
  '-....-': '-',
  '.-.-.-': '.',
  '-..-.': '/',
  '-----': '0',
  '.----': '1',
  '..---': '2',
  '...--': '3',
  '....-': '4',
  '.....': '5',
  '-....': '6',
  '--...': '7',
  '---..': '8',
  '----.': '9',
  '---...': ':',
  '-.-.-.': ';',
  '-...-': '=',
  '..--..': '?',
  '.--.-.': '@',
  '.-': 'A',
  '-...': 'B',
  '-.-.': 'C',
  '-..': 'D',
  '.': 'E',
  '..-.': 'F',
  '--.': 'G',
  '....': 'H',
  '..': 'I',
  '.---': 'J',
  '-.-': 'K',
  '.-..': 'L',
  '--': 'M',
  '-.': 'N',
  '---': 'O',
  '.--.': 'P',
  '--.-': 'Q',
  '.-.': 'R',
  '...': 'S',
  '-': 'T',
  '..-': 'U',
  '...-': 'V',
  '.--': 'W',
  '-..-': 'X',
  '-.--': 'Y',
  '--..': 'Z',
  '..--.-': '_',
  '...---...': 'SOS' ]

const map = {
  '.-': 'A',
  '-...': 'B',
  '-.-.': 'C',
  '-..': 'D',
  '.': 'E',
  '..-.': 'F',
  '--.': 'G',
  '....': 'H',
  '..': 'I',
  '.---': 'J',
  '-.-': 'K',
  '.-..': 'L',
  '--': 'M',
  '-.': 'N',
  '---': 'O',
  '.--.': 'P',
  '--.-': 'Q',
  '.-.': 'R',
  '...': 'S',
  '-': 'T',
  '..-': 'U',
  '...-': 'V',
  '.--': 'W',
  '-..-': 'X',
  '-.--': 'Y',
  '--..': 'Z',
  '-----': '0',
  '.----': '1',
  '..---': '2',
  '...--': '3',
  '....-': '4',
  '.....': '5',
  '-....': '6',
  '--...': '7',
  '---..': '8',
  '----.': '9'
}

const decodeMorse = function(morseCode) {
  const r1 = /\s{1}/
  const r3 = /\s{3}/
  return morseCode
    .trim()
    .split(r3)
    .map(code => code.split(r1).map(key => map[key]).join(''))
    .join(' ')
}

var decodeMorse = function(morseCode){
  const r1 = /\s{1}/
  const r3 = /\s{3}/
  return morseCode.trim()
    .split(r3)
    .map(code => code.split(r1).map(key => MORSE_CODE[key]).join(''))
    .join(' ')
}
